import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Klasa opisuje podzial zbioru na dwa podzbiory.
 * 
 * @author Ewa Byra (nr indeksu s6405)
 * 
 */
public class Partition {
	private List<Integer> firstSubSet;
	private List<Integer> secondSubSet;
	private List<Partition> neighbors;
	private int fit;

	/**
	 * Konstruktor klasy uzywany przy zwracaniu rozwiazania w klasycznym
	 * algorytmie genetycznym.
	 * 
	 * @param firstSubSet
	 *            Pierwszy podzbior.
	 * @param secondPartition
	 *            Drugi podzbior.
	 */
	public Partition(List<Integer> firstSubSet, List<Integer> secondSubSet) {
		this.firstSubSet = firstSubSet;
		this.secondSubSet = secondSubSet;
		Collections.sort(this.firstSubSet);
		Collections.sort(this.secondSubSet);
		this.neighbors = new ArrayList<>();
		this.fit = getDiffirence();
	}

	/**
	 * Metoda zwraca wartosc modulu roznicy sumy wartosci w podzbiorach.
	 * 
	 * @return Modul roznicy sum zbiorow.
	 */
	private int getDiffirence() {
		int firstSum = 0;
		int secondSum = 0;

		for (Integer i : this.firstSubSet) {
			firstSum += i;
		}

		for (Integer i : this.secondSubSet) {
			secondSum += i;
		}

		int diff = firstSum - secondSum;
		if (diff < 0)
			diff *= -1;

		return diff;
	}

	/**
	 * Metoda zwraca elementy pierwszego podbioru.
	 * 
	 * @return Lista elementow pierwszego podzbioru.
	 */
	public List<Integer> getFirstSubSet() {
		return firstSubSet;
	}

	/**
	 * Metoda zwraca elementy drugiego podbioru.
	 * 
	 * @return Lista elementow drugiego podzbioru.
	 */
	public List<Integer> getSecondSubSet() {
		return secondSubSet;
	}

	/**
	 * Metoda zwraca wartosc funkcji oceny.
	 * 
	 * @return Wartosc funkcji oceny.
	 */
	public int getFit() {
		return fit;
	}

	/**
	 * Metoda zwraca liste sasiednich rozwiazan.
	 * 
	 * @return Lista sasiadow.
	 */
	public List<Partition> getNeighbors() {
		return neighbors;
	}

	/**
	 * Metoda sluzy do dodawania sasiedniego rozwiazania.
	 * 
	 * @param p
	 *            Saisednie rozwiazanie do dodania.
	 */
	public void addNeighor(Partition p) {
		this.neighbors.add(p);
	}

	/**
	 * Metoda pornownuje dwa rozwiazania. Stosowana w celu unikniecia powtorzen.
	 * 
	 * @param p
	 *            Rozwiazanie do porownania.
	 * @return Wartosc 'true' jezeli rozwiazania sa identyczne.
	 */
	public boolean equals(Partition p) {
		boolean result = true;

		if (this.firstSubSet.size() != p.firstSubSet.size()
				|| secondSubSet.size() != p.secondSubSet.size()) {
			result = false;
		} else {
			for (int i = 0; i < this.firstSubSet.size(); i++) {
				if (this.firstSubSet.get(i) != p.firstSubSet.get(i)) {
					result = false;
					break;
				}
			}
			if (result) {
				for (int i = 0; i < this.secondSubSet.size(); i++) {
					if (this.secondSubSet.get(i) != p.secondSubSet.get(i)) {
						result = false;
						break;
					}
				}
			}
		}
		if (!result && this.firstSubSet.size() == p.secondSubSet.size()) {

			for (int i = 0; i < this.firstSubSet.size(); i++) {
				if (this.firstSubSet.get(i) != p.secondSubSet.get(i)) {
					result = false;
					break;
				}
			}
			result = true;
		}

		if (!result && this.secondSubSet.size() == p.firstSubSet.size()) {
			result = true;
			for (int i = 0; i < this.secondSubSet.size(); i++) {
				if (this.secondSubSet.get(i) != p.firstSubSet.get(i)) {
					result = false;
					break;
				}
			}
		}

		return result;

	}

	@Override
	public String toString() {
		return "" + firstSubSet + ", " + secondSubSet + " Przystosowanie = "
				+ fit;
	}

}
